package com.cyy.view.learn

import com.cyy.app.DDTRS_Styles
import com.cyy.model.Database
import com.cyy.model.Subscription
import com.cyy.model.Table
import com.cyy.view.*
import javafx.geometry.Insets
import javafx.geometry.Pos
import javafx.scene.control.Alert
import javafx.scene.control.TableView.CONSTRAINED_RESIZE_POLICY
import javafx.scene.layout.Priority
import tornadofx.*
import java.time.LocalDate
import java.time.Month

class ExpanderTable : Fragment("ExpanderTable") {
    val regions = listOf(
            Database(1, "Pacific Northwest", listOf(
                    Table(1, "D", "Seattle"),
                    Table(2, "W", "Portland")
            ).asObservable()),
            Database(2, "Alberta", listOf(
                    Table(3, "W", "Calgary")
            ).asObservable()),
            Database(3, "Midwest", listOf(
                    Table(4, "D", "Chicago"),
                    Table(5, "D", "Frankfort"),
                    Table(6, "W", "Indianapolis")
            ).asObservable())).asObservable()
    override val root = tableview(regions) {
        readonlyColumn("ID", Database::id)
        readonlyColumn("Name", Database::name)
        readonlyColumn("Tables", Database::tbls)
        rowExpander(expandOnDoubleClick = true) {
            paddingLeft = expanderColumn.width
            tableview(it.tbls) {
                readonlyColumn("ID", Table::id)
                readonlyColumn("Facility Code", Table::name)
                readonlyColumn("City", Table::kv)
            }
        }
    }

}

class BottomFrag : Fragment("drawer") {
    override val root = drawer {
        item("CancelView", expanded = true) {
            add(CancelView())
        }
        item("Selecting", expanded = true) {
            add(SelectingView())
        }
        item("Animation1", expanded = true) {
            add(AnimationDemo1())
        }
        item("Animation2", expanded = true) {
            add(AnimationDemo2())
        }
    }
}

class DataDrivenTableRowStyleView : View("Data Driven TableRow Style") {
    val data = listOf(
            Subscription(555666, "Firmware Update", LocalDate.of(2019, Month.DECEMBER, 31)),
            Subscription(9990, "Linux Distro", LocalDate.of(2018, Month.JANUARY, 1)),
            Subscription(17777, "Software App", LocalDate.of(2020, Month.MARCH, 15)),
            Subscription(20001, "Compression Utility", LocalDate.of(2019, Month.JULY, 1))
    ).asObservable()

    override val root = tableview(data) {

        column("ID", Subscription::idProperty)
        column("Product", Subscription::productNameProperty)
        column("Renewal", Subscription::renewalDateProperty) {
            cellFormat {
                text = it.toString()
                if (it.isBefore(LocalDate.now())) {
                    addClass(DDTRS_Styles.overdue)
                    if (this.tableRow != null) {
                        this.tableRow.addClass(DDTRS_Styles.highlighted)
                    }
                } else {
                    removeClass(DDTRS_Styles.overdue)
                    if (this.tableRow != null) {
                        this.tableRow.removeClass(DDTRS_Styles.highlighted)
                    }
                }
            }
        }

        columnResizePolicy = CONSTRAINED_RESIZE_POLICY

        prefWidth = 736.0
        prefHeight = 414.0
    }
}

class SalesRecord(var id: Int, office: String, year: String, quarter: String, totalSales: String) {

    val officeProperty = stringProperty(office)
    val yearProperty = stringProperty(year)
    val quarterProperty = stringProperty(quarter)
    val totalSalesProperty = stringProperty(totalSales)

    val objectId = nextObjectId() // always increasing

    companion object {
        private var idgen = 1 // faux static class member
        fun nextObjectId() = idgen++
    }

    override fun toString(): String {
        return "id=${id} objectId=${objectId} - ${officeProperty.value} ${yearProperty.value}/${quarterProperty
                .value} " +
                "sales=${totalSalesProperty.value}"
    }
}

enum class ActionType { ADD, UPDATE, DELETE }

class Action(val actionType: ActionType, val data: SalesRecord)

class SaveCompletedEvent : FXEvent()

class JournalController : Controller() {

    val data = mutableListOf(
            SalesRecord(990, "Home", "2018", "1", "100000"),
            SalesRecord(991, "NY", "2018", "1", "200000"),
            SalesRecord(992, "Home", "2018", "2", "125000"),
            SalesRecord(993, "NY", "2018", "2", "190000")
    ).asObservable()

    val pendingActions = mutableListOf<Action>()

    val consoleLog = stringProperty("")

    fun save() {
        pendingActions.forEach {
            when (it.actionType) {
                ActionType.ADD -> {
                    consoleLog += "Calling create service on ${it.data}\n"
                    if (it.data.id == -1) {
                        it.data.id = nextId()  // as though returned by a service call
                    }
                }
                ActionType.UPDATE -> consoleLog += "Calling update service on ${it.data}\n"
                ActionType.DELETE -> consoleLog += "Calling delete service on ${it.data}\n"
            }
        }
        pendingActions.clear()
        fire(SaveCompletedEvent())
    }

    fun newItem() {
        val newRecord = SalesRecord(-1, "Home", "2018", "3", "0.0")
        add(newRecord)
    }

    fun add(record: SalesRecord) {
        pendingActions.add(Action(ActionType.ADD, record))
        data.add(record)
    }

    fun delete(record: SalesRecord) {
        pendingActions.add(Action(ActionType.DELETE, record))
        data.remove(record)
    }

    fun update(record: SalesRecord) {
        pendingActions.add(Action(ActionType.UPDATE, record))
    }

    // used to generate fake ids from create call
    companion object {
        private var idgen = 8000
        fun nextId() = idgen++
    }
}

class JournalView : View("Journal App") {

    val c: JournalController by inject()

    override val root = vbox {

        button("+") { action { c.newItem() } }
        tableview(c.data) {

            isEditable = true

            column("Office", SalesRecord::officeProperty).makeEditable().setOnEditCommit { c.update(it.rowValue) }
            column("Year", SalesRecord::yearProperty).makeEditable().setOnEditCommit { c.update(it.rowValue) }
            column("Quarter", SalesRecord::quarterProperty).makeEditable().setOnEditCommit { c.update(it.rowValue) }
            column("TotalSalesProperty", SalesRecord::totalSalesProperty).makeEditable().setOnEditCommit { c.update(it.rowValue) }

            contextmenu {
                item("Delete") {
                    action {
                        if (selectedItem != null) {
                            c.delete(selectedItem!!)
                        }
                    }
                }
            }
            vgrow = Priority.ALWAYS
        }
        titledpane("Console") {
            textarea(c.consoleLog)
        }
        separator()
        hbox {
            button("Save") { action { c.save() } }
            alignment = Pos.TOP_RIGHT
            padding = Insets(4.0)
        }
        padding = Insets(4.0)
        spacing = 4.0
        prefWidth = 800.0
        prefHeight = 600.0
    }

    init {
        subscribe<SaveCompletedEvent> {
            alert(Alert.AlertType.INFORMATION, "Save Saved Successfully")
        }
    }
}
